package gitee.derumin.configurablefireworkexplosion.config;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.util.JsonHelper;
import net.minecraft.world.explosion.Explosion;
import org.apache.commons.io.FileUtils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;

public class ModConfig {
    private static ModConfig INSTANCE = new ModConfig();
    public static final int CONFIG_VERSION = 1;
    private static final Path CONFIG_PATH = FabricLoader.getInstance().getConfigDir()
            .resolve("configurable-firework-explosion")
            .resolve("configurable-firework-explosion.json");
    private boolean crossbowShotExplosion;
    private boolean handLaunchExplosion;
    private float baseExplosionPower;
    private float fireworkStarMultiplier;
    private boolean canDestroyBlocks;
    private boolean tntMode;
    private boolean canCreateFire;
    private boolean showParticles;

    private ModConfig(){
        this.crossbowShotExplosion = true;
        this.handLaunchExplosion = false;
        this.baseExplosionPower = 1.0f;
        this.fireworkStarMultiplier = 0.5f;
        this.canDestroyBlocks = true;
        this.tntMode = true;
        this.canCreateFire = false;
        this.showParticles = false;
    }
    public void init(){
        if (!CONFIG_PATH.getParent().toFile().exists() && !CONFIG_PATH.getParent().toFile().mkdir()){
            return;
        }
        File configFile = CONFIG_PATH.toFile();
        if (!configFile.exists()){
            this.createAndWriteToFile(configFile);
            return;
        }
        JsonObject configObject;
        try {
            configObject = JsonParser.parseString(FileUtils.readFileToString(configFile, StandardCharsets.UTF_8)).getAsJsonObject();
        } catch (IOException e) {
            return;
        }
        if (configObject.has("cross_bow_shot_explosion")) {
            this.crossbowShotExplosion = JsonHelper.getBoolean(configObject, "cross_bow_shot_explosion");
        }
        if (configObject.has("hand_launch_explosion")) {
            this.handLaunchExplosion = JsonHelper.getBoolean(configObject, "hand_launch_explosion");
        }
        if (configObject.has("base_explosion_power")) {
            this.baseExplosionPower = JsonHelper.getFloat(configObject, "base_explosion_power");
        }
        if (configObject.has("firework_star_multiplier")) {
            this.fireworkStarMultiplier = JsonHelper.getFloat(configObject, "firework_star_multiplier");
        }
        if (configObject.has("can_destroy_blocks")) {
            this.canDestroyBlocks = JsonHelper.getBoolean(configObject, "can_destroy_blocks");
        }
        if (configObject.has("tnt_mode")) {
            this.tntMode = JsonHelper.getBoolean(configObject, "tnt_mode");
        }
        if (configObject.has("can_create_fire")) {
            this.canCreateFire = JsonHelper.getBoolean(configObject, "can_create_fire");
        }
        if (configObject.has("show_particles")){
            this.showParticles = JsonHelper.getBoolean(configObject,"show_particles");
        }
        if (!configObject.has("config_version") || JsonHelper.getInt(configObject,"config_version") != CONFIG_VERSION){
            this.saveConfig();
        }
    }

    public void saveConfig(){
        if (!CONFIG_PATH.getParent().toFile().exists() && !CONFIG_PATH.getParent().toFile().mkdir()){
            return;
        }
        File configFile = CONFIG_PATH.toFile();
        if (!configFile.exists() || (configFile.exists() && configFile.delete())){
            this.createAndWriteToFile(configFile);
        }
    }

    private void createAndWriteToFile(File configFile){
        try {
            if (configFile.createNewFile()){
                try(BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(configFile,false))){
                    bufferedWriter.write(this.toFormattedString());
                }catch (IOException ignored){
                }
            }
        } catch (IOException ignored) {
        }
    }

    private String toFormattedString(){
        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        return gson.toJson(this.toJson());
    }

    private JsonObject toJson(){
        JsonObject object = new JsonObject();
        object.addProperty("?config_version","please do not modify this element");
        object.addProperty("config_version",CONFIG_VERSION);
        object.addProperty("?cross_bow_shot_explosion","determine whether a firework rocket shot by crossbow can explode");
        object.addProperty("cross_bow_shot_explosion",this.crossbowShotExplosion);
        object.addProperty("?hand_launch_explosion","determine whether firework rockets (except shot by crossbow) can explode");
        object.addProperty("hand_launch_explosion",this.handLaunchExplosion);
        object.addProperty("?base_explosion_power","determine the base power of the explosion (it would not work if the rocket was not made from firework stars)");
        object.addProperty("base_explosion_power",this.baseExplosionPower);
        object.addProperty("?firework_star_multiplier","determine how much each firework star can add to the explosion power");
        object.addProperty("firework_star_multiplier",this.fireworkStarMultiplier);
        object.addProperty("?can_destroy_blocks","determine whether the explosion can destroy blocks");
        object.addProperty("can_destroy_blocks",this.canDestroyBlocks);
        object.addProperty("?tnt_mode","determine whether the explosion can keep all drop items like tnt (regardless of the game rule tntExplosionDropDecay)");
        object.addProperty("tnt_mode",this.tntMode);
        object.addProperty("?can_create_fire","determine whether the explosion can create fire");
        object.addProperty("can_create_fire",this.canCreateFire);
        object.addProperty("?show_particles1","determine whether the explosion have explosion particles");
        object.addProperty("?show_particles2","for unknown reason, this did not work");
        object.addProperty("show_particles",this.showParticles);
        return object;
    }

    public static ModConfig getInstance(){
        return INSTANCE;
    }

    public static void reSet(){
        INSTANCE = new ModConfig();
    }

    public boolean isCrossbowShotExplosion(){
        return this.crossbowShotExplosion;
    }

    public boolean isHandLaunchExplosion(){
        return this.handLaunchExplosion;
    }

    public float getBaseExplosionPower(){
        return this.baseExplosionPower;
    }

    public float getFireworkStarMultiplier(){
        return this.fireworkStarMultiplier;
    }

    public Explosion.DestructionType getDestructionType(){
        if (!this.canDestroyBlocks){
            return Explosion.DestructionType.KEEP;
        }else if (this.tntMode){
            return Explosion.DestructionType.DESTROY;
        }
        return Explosion.DestructionType.DESTROY_WITH_DECAY;
    }

    public boolean isCanCreateFire(){
        return this.canCreateFire;
    }

    public boolean isShowParticles(){
        return this.showParticles;
    }
}
